﻿using Casamiel.Common;
using Casamiel.Domain.Entity;
using Casamiel.Domain.Request;
using Casamiel.Domain.Request.IC;
using Casamiel.Domain.Response;
using Casamiel.Domain.Response.IC;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Casamiel.Application.Services
{
    /// <summary>
    /// 
    /// </summary>
    public sealed class SimpleStringCypher
    {
        private RijndaelManaged RM;
        /// <summary>
        /// 构造函数指定加密密钥
        /// </summary>
        /// <param name="secret">加密密钥</param>
        public SimpleStringCypher(String secret)
        {
            var keyBytes = PrepareAesKey(secret);
            RM = new System.Security.Cryptography.RijndaelManaged {
                Mode = System.Security.Cryptography.CipherMode.ECB,
                Padding = System.Security.Cryptography.PaddingMode.PKCS7,

                KeySize = 128,
                BlockSize = 128,
                Key = keyBytes,
                IV = keyBytes
            };
        }
        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="plaintext">需加密的字符串</param>
        /// <returns>加密后并经过 base64 编码的字符串</returns>
        public string Encrypt(string plaintext)
        {
            if (string.IsNullOrWhiteSpace(plaintext)) return null;
            Byte[] plaintextBytes = Encoding.UTF8.GetBytes(plaintext);
            ICryptoTransform cTransform = RM.CreateEncryptor();
            Byte[] resultArray = cTransform.TransformFinalBlock(plaintextBytes, 0, plaintextBytes.Length);
            return URLSafeBase64Reflow(Convert.ToBase64String(resultArray, 0, resultArray.Length));
        }

        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="codedText">需加密的字符串</param>
        /// <returns>加密后并经过 base64 编码的字符串</returns>
        public string Decrypt(string codedText)
        {
            if (string.IsNullOrWhiteSpace(codedText)) return null;

#pragma warning disable CA1062 // Validate arguments of public methods
            Byte[] toDeryptArray = Convert.FromBase64String(AutomaticallyPad(NormalBase64Reflow(codedText)));
#pragma warning restore CA1062 // Validate arguments of public methods
            ICryptoTransform cTransform = RM.CreateDecryptor();
            Byte[] resultArray = cTransform.TransformFinalBlock(toDeryptArray, 0, toDeryptArray.Length);
            return Encoding.UTF8.GetString(resultArray);
        }

        private static string AutomaticallyPad(string base64)
        {
            return base64.PadRight(base64.Length + (4 - base64.Length % 4) % 4, '=');
        }

        private static string URLSafeBase64Reflow(string base64)
        {
            return base64.Replace("=", String.Empty, StringComparison.CurrentCulture).Replace('+', '-').Replace('/', '_');
        }

        private static string NormalBase64Reflow(string base64)
        {
            return base64.Replace("=", String.Empty, StringComparison.CurrentCulture).Replace('-', '+').Replace('_', '/');
        }

        private static byte[] PrepareAesKey(string key)
        {
            Byte[] keyBinary = Convert.FromBase64String(AutomaticallyPad(NormalBase64Reflow(key)));
            var keyBytes = new byte[16];
            Array.Copy(keyBinary, keyBytes, Math.Min(keyBytes.Length, keyBinary.Length));
            return keyBytes;
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public sealed class NetICService : INetICService
    {
        private readonly string token = "";
        private readonly string appkey = "";
        private readonly string signKey = "";
        private readonly IHttpClientFactory _clientFactory;
        private readonly SimpleStringCypher _sc;
        private string appurl = "";
        private readonly IcServiceSettings _settings;
        private readonly NLog.ILogger logger = NLog.LogManager.GetLogger("IicApiService");
        private readonly JsonSerializerSettings jsonSerializerSettings;


        public NetICService(IOptionsSnapshot<IcServiceSettings> settings, IHttpClientFactory clientFactory)
        {
            if (settings == null) {
                throw new ArgumentNullException(nameof(settings));
            }
            token = settings.Value.token;
            appkey = settings.Value.appKey;
            _clientFactory = clientFactory;
            signKey = settings.Value.signKey;
            _sc = new SimpleStringCypher(appkey);
            _settings = settings.Value;

            jsonSerializerSettings = new JsonSerializerSettings {
                ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
            };
        }
        /// <summary>
        /// Sign the specified prestr, keyPre, keyAfter and _input_charset.
        /// </summary>
        /// <returns>The sign.</returns>
        /// <param name="prestr">Prestr.</param>
        /// <param name="keyPre">Key pre.</param>
        /// <param name="keyAfter">Key after.</param>
        /// <param name="inputCharset">Input charset.</param>
        public static string Sign(string prestr, string keyPre, string keyAfter, string inputCharset = "utf-8")
        {
            StringBuilder sb = new StringBuilder(32);

            prestr = keyPre + prestr + keyAfter;

            using (MD5 md5 = new MD5CryptoServiceProvider()) {
                byte[] t = md5.ComputeHash(Encoding.GetEncoding(inputCharset).GetBytes(prestr));
                for (int i = 0; i < t.Length; i++) {
#pragma warning disable CA1305 // 指定 IFormatProvider
                    sb.Append(t[i].ToString("x").PadLeft(2, '0'));
#pragma warning restore CA1305 // 指定 IFormatProvider
                }
                return sb.ToString();
            }
        }

        /// <summary>
        /// Geticconsumecode the specified cardno.
        /// </summary>
        /// <returns>The geticconsumecode.</returns>
        /// <param name="cardno">Cardno.</param>
        public async Task<Tuple<ICConsumeCodeRsp, int, string>> Icconsumecode(string cardno,int Datasource)
        {
            var content = "{\"wxopenid\":\"\",\"phoneno\":\"\",\"cardno\":\"" + cardno + "\",\"datasource\":"+ Datasource + ",\"timestamp\":\"" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CreateSpecificCulture("en-US")) + "\"}";
            //var _content = sc.Encrypt(content);
            //string signData = Sign("token" + token + "content" + content, signKey, signKey);
            var result = await PostAsync(content, "icapi/icconsumecode").ConfigureAwait(false);
            if (result.code == 0) {
                var d = JsonConvert.DeserializeObject<ICConsumeCodeRsp>(result.content);
                return new Tuple<ICConsumeCodeRsp, int, string>(d, 0, result.msg);
            }
            return new Tuple<ICConsumeCodeRsp, int, string>(null, result.code, result.msg);
        }


        /// <summary>
        /// 门店核销
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<ICResult> Icorderpickup(OrderpickupRequest data)
        {
            if (data == null) {
                throw new ArgumentNullException(typeof(OrderpickupRequest).Name);
            }
            data.Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CurrentCulture);


            var content = JsonConvert.SerializeObject(data, Formatting.None, jsonSerializerSettings);
            var model = await PostAsync(content, "icapi/icorderpickup").ConfigureAwait(false);
            logger.Trace($"icorderpickup,Result:{JsonConvert.SerializeObject(model)},Req:{JsonConvert.SerializeObject(data)}");
            return model;
        }

        /// <summary>
        /// 绑定会员卡
        /// </summary>
        /// <param name="cardno">卡号</param>
        /// <param name="mobile">手机号</param>
        /// <param name="datasource"></param>
        /// <returns></returns>
        public async Task<ICResult> Icregist(string cardno, string mobile, int datasource)
        {
            var content = "{\"cardno\":\"" + cardno + "\",\"phoneno\":\"" + mobile + "\",\"datasource\":" + datasource + ",\"phonesms\":\"\",\"timestamp\":\"" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CurrentCulture) + "\"}";
            logger.Trace($"绑定会员卡：{content}");
            //var _content = sc.Encrypt(content);
            //string signData = Sign("token" + token + "content" + content, signKey, signKey);
            var model = await PostAsync(content, "icapi/icregist").ConfigureAwait(false);
            logger.Trace($"绑定会员卡：{JsonConvert.SerializeObject(model)}");
            return model;
        }

        /// <summary>
        /// 获取券码
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<ICResult> TMTicket(TMTicketRequest request)
        {
            if (request is null) {
                throw new ArgumentNullException(nameof(request));
            }
            request.Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CreateSpecificCulture("en-US"));
            var content = JsonConvert.SerializeObject(request, Formatting.None, jsonSerializerSettings);
            logger.Trace($"获取券码：{content}");
            //var _content = sc.Encrypt(content);
            //string signData = Sign("token" + token + "content" + content, signKey, signKey);
            var model = await PostAsync(content, "icapi/tmticket").ConfigureAwait(false);
            logger.Trace($"获取券码：{JsonConvert.SerializeObject(model)}");
            return model;
        }


        public async Task<ICResult> IcModify(IcModifyRequest request)
        {
            if (request is null) {
                throw new ArgumentNullException(nameof(request));
            }
            request.Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CreateSpecificCulture("en-US"));
            var content = JsonConvert.SerializeObject(request, Formatting.None, jsonSerializerSettings);
            logger.Trace($"IcModify：{content}");
            //var _content = sc.Encrypt(content);
            //string signData = Sign("token" + token + "content" + content, signKey, signKey);
            var model = await PostAsync(content, "icapi/icmodify").ConfigureAwait(false);
            logger.Trace($"IcModify：{JsonConvert.SerializeObject(model)}");
            return model;
        }
        /// <summary>
        /// 变更券码
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<ICResult> Tmticketchange(TmticketchangeRequest request)
        {
            if (request is null) {
                throw new ArgumentNullException(nameof(request));
            }
            request.Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CreateSpecificCulture("en-US"));
            var content = JsonConvert.SerializeObject(request, Formatting.None, jsonSerializerSettings);
            logger.Trace($"变更券码：{content}");
            //var _content = sc.Encrypt(content);
            //string signData = Sign("token" + token + "content" + content, signKey, signKey);
            var model = await PostAsync(content, "icapi/tmticketchange").ConfigureAwait(false);
            logger.Trace($"变更券码：{JsonConvert.SerializeObject(model)}");
            return model;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<ICResult> Icticketchange(IcticketchangeRequest request)
        {
            if (request is null) {
                throw new ArgumentNullException(nameof(request));
            }
            request.Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CreateSpecificCulture("en-US"));
            var content = JsonConvert.SerializeObject(request, Formatting.None, jsonSerializerSettings);
            logger.Trace($"转赠：{content}");
            //var _content = sc.Encrypt(content);
            //string signData = Sign("token" + token + "content" + content, signKey, signKey);
            var model = await PostAsync(content, "icapi/icticketchange").ConfigureAwait(false);
            logger.Trace($"转赠：{JsonConvert.SerializeObject(model)}");
            return model;
        }

        /// <summary>
        /// 绑定员工卡
        /// </summary>
        /// <param name="cardno">卡号</param>
        /// <param name="mobile">手机号</param>
        /// <param name="datasource"></param>
        /// <returns></returns>
        public async Task<ICResult> SaffIcregist(string cardno, string mobile, int datasource)
        {
            var content = "{\"cardno\":\"" + cardno + "\",\"ictype\":3,\"phoneno\":\"" + mobile + "\",\"datasource\":" + datasource + ",\"phonesms\":\"\",\"timestamp\":\"" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CurrentCulture) + "\"}";
            logger.Trace($"绑定会员卡：{content}");
            //var _content = sc.Encrypt(content);
            //string signData = Sign("token" + token + "content" + content, signKey, signKey);
            var model = await PostAsync(content, "icapi/icregist").ConfigureAwait(false);
            logger.Trace($"绑定员员卡：{JsonConvert.SerializeObject(model)}");
            return model;
        }

        /// <summary>
        /// 
        /// </summary>
        internal class TicketLimitExt
        {
            /// <summary>
            /// 
            /// </summary>
            public bool icticket;
            /// <summary>
            /// 
            /// </summary>
            public long ticketid;
        }
        /// <summary>
        /// 
        /// </summary>
        internal class TicketLimitTicketcodeExt
        {
            /// <summary>
            /// 
            /// </summary>
            public bool Icticket;
            /// <summary>
            /// 
            /// </summary>
            public string Ticketcode;
        }
        /// <summary>
        /// 
        /// </summary>
        internal class TicketLimitProductIdExt
        {
            /// <summary>
            /// 
            /// </summary>
            public bool icticket;
            /// <summary>
            /// 
            /// </summary>
            public long productid;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="shopid"></param>
        /// <param name="Ids"></param>
        /// <param name="type">0productid,1-ticketid</param>
        /// <param name="Icticket">true 会员券</param>
        /// <returns></returns>
        public async Task<ICResult> TicketLimit(int shopid, List<long> Ids, int type, bool Icticket, CancellationToken cancellationToken)
        {
            if (Ids == null) {
                throw new ArgumentNullException(nameof(Ids));
            }

            string content = "";
            switch (type) {
                case 1:
                    var dic = new List<TicketLimitExt>();
                    foreach (var item in Ids) {
                        dic.Add(new TicketLimitExt { icticket = Icticket, ticketid = item });
                    }
                    var data = new { shopid, tickets = dic, datasource = 15, timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CreateSpecificCulture("en-US")) };
                    content = JsonConvert.SerializeObject(data, Formatting.None, jsonSerializerSettings);
                    break;

                default:
                    var productids = new List<TicketLimitProductIdExt>();
                    foreach (var item in Ids) {
                        productids.Add(new TicketLimitProductIdExt { icticket = Icticket, productid = item });
                    }
                    var datas = new { shopid, tickets = productids, datasource = 15, timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CreateSpecificCulture("en-US")) };
                    content = JsonConvert.SerializeObject(datas, Formatting.None, jsonSerializerSettings);

                    break;
            }
            Console.WriteLine(content);
            var result = await PostAsync(content, "icapi/ticketlimit", cancellationToken).ConfigureAwait(false);
            return result;
        }

        public async Task<ICResult> TicketLimitExts(int shopid, List<long> ids, int type, bool Icticket, List<ProductItem> products)
        {
            if (ids == null) {
                throw new ArgumentNullException(nameof(ids));
            }

            string content = "";
            switch (type) {
                case 1:
                    var dic = new List<TicketLimitExt>();
                    foreach (var item in ids) {
                        dic.Add(new TicketLimitExt { icticket = Icticket, ticketid = item });
                    }
                    var data = new { shopid, tickets = dic, datasource = 15, product = products, timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CreateSpecificCulture("en-US")) };
                    content = JsonConvert.SerializeObject(data, Formatting.None, jsonSerializerSettings);
                    break;

                default:
                    var productids = new List<TicketLimitProductIdExt>();
                    foreach (var item in ids) {
                        productids.Add(new TicketLimitProductIdExt { icticket = Icticket, productid = item });
                    }
                    var datas = new { shopid, tickets = productids, datasource = 15, product = products, timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CreateSpecificCulture("en-US")) };
                    content = JsonConvert.SerializeObject(datas, Formatting.None, jsonSerializerSettings);

                    break;
            }
            Console.WriteLine(content);
            var result = await PostAsync(content, "icapi/ticketlimit").ConfigureAwait(false);
            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="shopid"></param>
        /// <param name="ticketcode"></param>
        /// <returns></returns>
        public async Task<ICResult> TicketLimit(int shopid, string ticketcode)
        {
            var dic = new List<TicketLimitTicketcodeExt> {
                new TicketLimitTicketcodeExt { Icticket = false, Ticketcode = ticketcode }
            };
            var data = new { shopid, tickets = dic, datasource = 15, timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CreateSpecificCulture("en-US")) };
            var content = JsonConvert.SerializeObject(data, Formatting.None, jsonSerializerSettings);

            var result = await PostAsync(content, "icapi/ticketlimit").ConfigureAwait(false);
            return result;
        }


        public async Task<ICResult> ICTicketExpireQuery(string Expirestartdate, string Expireenddate)
        {
            var data = new { Expireenddate, Expirestartdate, Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CreateSpecificCulture("en-US")) };

            var content = JsonConvert.SerializeObject(data, Formatting.None, jsonSerializerSettings);
            var model = await PostAsync(content, "icapi/ICTicketExpireQuery").ConfigureAwait(false);
            logger.Trace($"Tmticketexpirequyer：{JsonConvert.SerializeObject(model)}");
            return model;
        }
        /// <summary>
        /// Posts the async.
        /// </summary>
        /// <returns>The async.</returns>
        /// <param name="content">Content.</param>
        /// <param name="servicename">Servicename.</param>
        private async Task<ICResult> PostAsync(string content, string servicename, CancellationToken cancellationToken = default)
        {
            //  var _sc = new SimpleStringCypher(appkey);
            var _content = _sc.Encrypt(content);
            var data = "";
            string signData = Sign("token" + token + "content" + content, signKey, signKey);
            System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();

            var paramList = new List<KeyValuePair<String, String>>
            {
                new KeyValuePair<String, String>("token", token),
                new KeyValuePair<String, String>("sign", signData),
                new KeyValuePair<String, String>("content", _content)
            };



            Random a = new Random();
            var aaa = a.NextDouble();
            HttpClient client;
            if (aaa < 0.5) {
                client = _clientFactory.CreateClient("icapi");
                appurl = _settings.appUrls[0].Url;
            } else {
                client = _clientFactory.CreateClient("icapi1");
                appurl = _settings.appUrls[1].Url;
            }
            try {
                watch.Start();
                using (var request = new HttpRequestMessage(HttpMethod.Post, servicename) {
                    Content = new FormUrlEncodedContent(paramList)
                }) {
                    using (var response = await client.SendAsync(request, cancellationToken).ConfigureAwait(false)) {

                        watch.Stop();
                        if (watch.ElapsedMilliseconds > 100) {
                            if (servicename != "icapi/productstockquery") {
                                logger.Warn($"new:data:{content},url：{appurl + servicename}，执行时间{ watch.ElapsedMilliseconds}毫秒");
                                Console.WriteLine($"url：{appurl + servicename}，执行时间{ watch.ElapsedMilliseconds}毫秒");
                            }
                        }
                        string result = "";
                        if (response.IsSuccessStatusCode) {
                            using (var s = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false)) {
                                //result = await response.Content.ReadAsStringAsync();
                                System.Xml.XmlDocument xmld = new System.Xml.XmlDocument();
                                xmld.Load(s);
                                result = xmld.InnerText;
                            }

                        } else {
                            logger.Error($"{servicename},{response.StatusCode}");
                            return new ICResult { code = 999, content = "", msg = "出错了" };
                        }

                        ICResult jdata;
                        //try
                        //{
                        //    response = await _client.PostAsync(new Uri(appurl + servicename), new FormUrlEncodedContent(paramList));
                        if (response.StatusCode == System.Net.HttpStatusCode.OK) {
                            // data = response.Content.ReadAsStringAsync().Result;
                            //var dynamicdata = JsonConvert.DeserializeObject<dynamic>(result);
                            //string _data = dynamicdata.ToString();
                            jdata = JsonConvert.DeserializeObject<ICResult>(result);
                            if (jdata == null) {
                                logger.Error($"{servicename},{response.StatusCode}");
                                return new ICResult { code = 999, content = "", msg = "出错了" };
                            }
                            if (jdata.content.Trim().Length > 0) {
                                jdata.content = _sc.Decrypt(jdata.content);
                                // var psigndata = Sign("token" + token + "content" + jdata.content, signKey, signKey);
                            }
                        } else {
                            logger.Error($"StatusCode:{response.StatusCode},data:{content},url：{appurl},servicename:{servicename},data:{data}");
                            throw new ArgumentException(response.StatusCode.ToString());
                        }

                        return jdata;
                    }
                }


                // logger.Info(data);
            } catch (System.Net.Sockets.SocketException ex) {
                logger.Error($"data:{content},url：{appurl},servicename:{servicename},data:{data}");
                logger.Error(ex.StackTrace);
                throw;
            } catch (TaskCanceledException ex) {
                logger.Error($"data:{content},url：{appurl},servicename:{servicename},data:{data}");
                logger.Error(ex.Message);
                throw;
            }
        }

        /// <summary>
        /// Iclessquery the specified CardNO and datasource.
        /// </summary>
        /// <returns>The iclessquery.</returns>
        /// <param name="CardNO">Card no.</param>
        /// <param name="datasource">Datasource.</param>
        public async Task<ICResult> Iclessquery(string CardNO, int datasource)
        {
            var data = new { cardno = CardNO, datasource, timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CreateSpecificCulture("en-US")) };
            //logger.Trace($"查余额：{content}");
            var model = await PostAsync(JsonConvert.SerializeObject(data), "icapi/iclessquery").ConfigureAwait(false);
            //logger.Trace($"查余额：{JsonConvert.SerializeObject(model)}");
            return model;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="req"></param>
        /// <returns></returns>
        public async Task<ICProductStockQueryRoot> Productstockquery(ProductStockQueryReq req)
        {
            if (req == null) {
                throw new ArgumentNullException(nameof(req));
            }

            req.timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CreateSpecificCulture("en-US"));
            var content = JsonConvert.SerializeObject(req, Formatting.None, jsonSerializerSettings);
            // Console.WriteLine(content);
            //var _content = sc.Encrypt(content);
            //string signData = Sign("token" + token + "content" + content, signKey, signKey);
            var tmodel = await PostAsync(content, "icapi/productstockquery").ConfigureAwait(false);
            if (tmodel.code == 0) {
                var root = JsonConvert.DeserializeObject<ICProductStockQueryRoot>(tmodel.content);
                return root;
            } else {
                return new ICProductStockQueryRoot();
            };
            //Console.WriteLine(JsonConvert.SerializeObject(tmodel));

        }
        /// <summary>
        /// Icconsume the specified .
        /// </summary>
        /// <returns>The icconsume.</returns>
        /// <param name="">.</param>
        public async Task<ICResult> Icconsume(IcconsumeReq req)
        {
            if (req == null) {
                throw new ArgumentNullException(nameof(req));
            }
            if (req.Datasource == 0) {
                req.Datasource = 15;
            }
            req.Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CreateSpecificCulture("en-US"));
            var content = JsonConvert.SerializeObject(req, Formatting.None, jsonSerializerSettings);

            var model = await PostAsync(content, "icapi/icconsume").ConfigureAwait(false);
            logger.Trace($"icconsume:req:{content},rsp:{JsonConvert.SerializeObject(model)}");
            return model;
        }

        public async Task<ICResultExt> Geticticket(GetTicticketReq req, CancellationToken token)
        {
            if (req == null) {
                throw new ArgumentNullException(nameof(req));
            }
            req.Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CreateSpecificCulture("en-US"));
            var content = JsonConvert.SerializeObject(req, Formatting.None, jsonSerializerSettings);
            //var _content = sc.Encrypt(content);
            //string signData = Sign("token" + token + "content" + content, signKey, signKey);
            return await PostExtAsync(content, "icapi/icticket", token).ConfigureAwait(false);
        }

        /// <summary>
        /// Posts the ext async.
        /// </summary>
        /// <returns>The ext async.</returns>
        /// <param name="content">Content.</param>
        /// <param name="servicename">Servicename.</param>
        private async Task<ICResultExt> PostExtAsync(string content, string servicename, CancellationToken cancellationToken = default)
        {
            var _content = _sc.Encrypt(content);
            string signData = Sign("token" + token + "content" + content, signKey, signKey);
            System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
            watch.Start();
            List<KeyValuePair<String, String>> paramList = new List<KeyValuePair<String, String>>
            {
                new KeyValuePair<String, String>("token", token),
                new KeyValuePair<String, String>("sign", signData),
                new KeyValuePair<String, String>("content", _content)
            };

            var data = "";
            //HttpResponseMessage response = new HttpResponseMessage();
            Random a = new Random();
            var aaa = a.NextDouble();
            HttpClient client;
            if (aaa < 0.5) {
                client = _clientFactory.CreateClient("icapi");
                appurl = _settings.appUrls[0].Url;
            } else {
                client = _clientFactory.CreateClient("icapi1");
                appurl = _settings.appUrls[1].Url;
            }
            try {
                using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, servicename) {
                    Content = new FormUrlEncodedContent(paramList)
                }) {
                    using (var response = await client.SendAsync(request, cancellationToken).ConfigureAwait(false)) {
                        if (response.IsSuccessStatusCode) {
                            //data = await response.Content.ReadAsStringAsync();
                            using (var s = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false)) {
                                System.Xml.XmlDocument xml = new System.Xml.XmlDocument();
                                xml.Load(s);
                                data = xml.InnerText;
                            }

                        } else {
                            logger.Error(response.Content.ReadAsStringAsync(cancellationToken).Result);
                            throw new ArgumentException(response.StatusCode.ToString());
                        }
                    }
                }


                // logger.Info(data);
            } catch (System.Net.Sockets.SocketException ex) {
                logger.Error($"content:{content},url：{appurl + servicename}");
                logger.Error(ex.StackTrace);
                throw;
            } catch (TaskCanceledException ex) {
                logger.Error($"content:{content},url：{appurl + servicename}");
                logger.Error(ex.StackTrace);
                throw;
            }
            watch.Stop();
            if (watch.ElapsedMilliseconds > 100) {
                logger.Warn($"content:{content},url：{appurl + servicename}，执行时间{ watch.ElapsedMilliseconds}毫秒");
                // Console.WriteLine($"url：{appurl + servicename}，执行时间{ watch.ElapsedMilliseconds}毫秒");
            }

            var jdata = JsonConvert.DeserializeObject<ICResultExt>(data);
            if (jdata.content.Trim().Length > 0) {
                jdata.content = _sc.Decrypt(jdata.content);
                // var psigndata = Sign("token" + token + "content" + jdata.content, signKey, signKey);
            }
            return jdata;
        }

        /// <summary>
        /// Icconsumeback the specified req.
        /// </summary>
        /// <returns>The icconsumeback.</returns>
        /// <param name="req">Req.</param>
        public async Task<ICResult> Icconsumeback(IcConsumeBackReq req)
        {
            if (req == null) {
                throw new ArgumentNullException(nameof(req));
            }
            req.Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CreateSpecificCulture("en-US"));
            var content = JsonConvert.SerializeObject(req, Formatting.None, jsonSerializerSettings);
            logger.Trace($"icconsumeback:{content}");
            //var _content = sc.Encrypt(content);
            //string signData = Sign("token" + token + "content" + content, signKey, signKey);
            var model = await PostAsync(content, "icapi/icconsumeback").ConfigureAwait(false);
            logger.Trace($"icconsume:{JsonConvert.SerializeObject(model)}");
            return model;
        }

        /// <summary>
        /// Icconsumepay the specified req.
        /// </summary>
        /// <returns>The icconsumepay.</returns>
        /// <param name="req">Req.</param>
        public async Task<ICResult> Icconsumepay(IcConsumepayReq req)
        {
            if (req == null) {
                throw new ArgumentNullException(nameof(req));
            }
            req.Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CreateSpecificCulture("en-US"));
            var content = JsonConvert.SerializeObject(req, Formatting.None, jsonSerializerSettings);
            logger.Trace($"icconsumepay:{content}");
            var model = await PostAsync(content, "icapi/icconsumepay").ConfigureAwait(false);
            logger.Trace($"icconsumepay:{JsonConvert.SerializeObject(model)}");
            return model;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="req"></param>
        /// <returns></returns>
        public async Task<ICResult> Thirdorder(IcconsumeReq req)
        {
            if (req == null) {
                throw new ArgumentNullException(nameof(req));
            }
            req.Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CreateSpecificCulture("en-US"));
            var content = JsonConvert.SerializeObject(req, Formatting.None, jsonSerializerSettings);

            var model = await PostAsync(content, "icapi/thirdorder").ConfigureAwait(false);
            logger.Trace($"icconsume:{JsonConvert.SerializeObject(model)}");
            return model;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
		/// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task<ICPriceRsp> Icprice(IcPriceReq data, CancellationToken cancellationToken)
        {
            if (data == null) {
                throw new ArgumentNullException(nameof(data));
            }

            data.Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CreateSpecificCulture("en-US"));
            var content = JsonConvert.SerializeObject(data, Formatting.None, jsonSerializerSettings);
            var tmodel = await PostAsync(content, "icapi/icprice", cancellationToken).ConfigureAwait(false);
            if (tmodel.code == 0) {
                return JsonConvert.DeserializeObject<ICPriceRsp>(tmodel.content);
            }
            //Console.WriteLine(tmodel.content);
            throw new Exception(tmodel.msg);

        }

        public async Task<ICResult> Tmticketquery(TmticketqueryReq req)
        {
            if (req == null) {
                throw new ArgumentNullException(nameof(req));
            }
            req.timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CreateSpecificCulture("en-US"));
            var content = JsonConvert.SerializeObject(req, Formatting.None, jsonSerializerSettings);
            logger.Trace($"tmticketquery：{content}");
            //var _content = sc.Encrypt(content);
            //string signData = Sign("token" + token + "content" + content, signKey, signKey);
            var tmodel = await PostAsync(content, "icapi/tmticketquery").ConfigureAwait(false);
            logger.Trace($"tmticketquery:req:{content},rsp:{JsonConvert.SerializeObject(tmodel)}");
            //Console.WriteLine(tmodel.content);
            //var aa = JsonConvert.DeserializeObject<ICPriceRsp>(tmodel.content);
            //Console.WriteLine(JsonConvert.SerializeObject(aa));
            return tmodel;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<ICResult> Icticketlargess(AddTicketsReq data)
        {
            if (data == null) {
                throw new ArgumentNullException(nameof(data));
            }
            data.Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CurrentCulture);
            var content = JsonConvert.SerializeObject(data, Formatting.None, jsonSerializerSettings);
            var model = await PostAsync(content, "icapi/ICTicketLargess").ConfigureAwait(false);
            logger.Trace($"icticket，req:{JsonConvert.SerializeObject(content)},reuslt:{JsonConvert.SerializeObject(model)}");
            return model;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<ICResult> Icticketlargesscancel(TicketLargessCancelReq req)
        {
            if (req == null) {
                throw new ArgumentNullException(nameof(req));
            }
            req.Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CurrentCulture);
            var content = JsonConvert.SerializeObject(req, Formatting.None, jsonSerializerSettings);
            var model = await PostAsync(content, "icapi/icticketlargesscancel").ConfigureAwait(false);
            logger.Trace($"icticket，req:{JsonConvert.SerializeObject(content)},reuslt:{JsonConvert.SerializeObject(model)}");
            return model;
        }


        /// <summary>
        /// Thirdorderback the specified data.
        /// </summary>
        /// <returns>The thirdorderback.</returns>
        /// <param name="data">Data.</param>
        public async Task<ICResult> Thirdorderback(ThirdOrderBackReq data)
        {
            if (data == null) {
                throw new ArgumentNullException(nameof(data));
            }
            data.Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CurrentCulture);
            var content = JsonConvert.SerializeObject(data, Formatting.None, jsonSerializerSettings);
            var model = await PostAsync(content, "icapi/ThridOrderBack").ConfigureAwait(false);
            logger.Trace($"thirdorderback,req:{content},result:{JsonConvert.SerializeObject(model)}");
            return model;
        }

        /// <summary>
		/// 
		/// </summary>
		/// <param name="requst"></param>
		/// <returns></returns>
		public async Task<ICResult> ICPushPlan(ICPushPlanRequst requst)
        {
            if (requst == null) {
                throw new ArgumentNullException(nameof(requst));
            }
            requst.Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CurrentCulture);
            var content = JsonConvert.SerializeObject(requst, Formatting.None, jsonSerializerSettings);
            var model = await PostAsync(content, "icapi/ICPushPlan").ConfigureAwait(false);
            logger.Trace($"ICPushPlan,req:{content},result:{JsonConvert.SerializeObject(model)}");
            return model;
        }

        /// <summary>
		/// 
		/// </summary>
		/// <param name="request"></param>
		/// <returns></returns>
		public async Task<ICResult> ICtransfer(ICTransferRequest request)
        {
            if (request == null) {
                throw new ArgumentNullException(nameof(request));
            }
            request.Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CurrentCulture);

            var content = JsonConvert.SerializeObject(request, Formatting.None, jsonSerializerSettings);
            if (request.Transfermoney == 0) {
                var data = new { request.Cardno, request.Cardnosource, request.Datasource, request.Timestamp };
                content = JsonConvert.SerializeObject(data, Formatting.None, jsonSerializerSettings);
            }
            var model = await PostAsync(content, "icapi/ICtransfer").ConfigureAwait(false);
            logger.Trace($"ICtransfer,req:{content},result:{JsonConvert.SerializeObject(model)}");
            return model;
        }


        /// <summary>
        /// 注册会员卡
        /// </summary>
        /// <param name="mobile"></param>
        /// <param name="datasource">11、微信；15、手机APP(默认)；16、PAD</param>
        /// <param name="sex"></param>
        /// <param name="shopid"></param>
        /// <returns></returns>
        public async Task<ICResult> Icselfregist(string mobile, int datasource, int shopid, string sex = "1")
        {
            /*
            //            {
            //”phoneno”:”13912345678”,
            //“name”:”张三”,
            //“sex”:”0”,
            //“idtype”:”1”,
            //“idcard”:”330xxxxxxxxxxxxxxx”,
            //“birthday”:”1990 - 01 - 02”,
            //”phonesms”:”123654”,
            //”timestamp”:”2016 - 02 - 16 12:01:02”
            //}
            */
            var content = "{\"phoneno\":\"" + mobile + "\",\"datasource\":" + datasource + ",\"name\":\"1\",\"sex\":\"" + sex + "\",\"idtype\":\"1\",\"birthday\":\"\",\"phonesms\":\"\",\"timestamp\":\"" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CurrentCulture) + "\"}";
            if (shopid > 0) {
                content = "{\"phoneno\":\"" + mobile + "\",\"shopid\":" + shopid + ",\"datasource\":" + datasource + ",\"name\":\"1\",\"sex\":\"" + sex + "\",\"idtype\":\"1\",\"birthday\":\"\",\"phonesms\":\"\",\"timestamp\":\"" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CurrentCulture) + "\"}";

            }

            //var _content = sc.Encrypt(content);
            //string signData = Sign("token" + token + "content" + content, signKey, signKey);
            var zmodel = await PostAsync(content, "icapi/Icselfregist").ConfigureAwait(false);
            logger.Trace($"{JsonConvert.SerializeObject(zmodel)}");
            if (zmodel.code == 0) {
                logger.Trace($"[{mobile}]注册会员卡{zmodel.content}");
            }
            return zmodel;
        }

        /// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
        public async Task<ICResult> ICconsumepayprequery(ICconsumepayprequeryRequest request)
        {
            if (request == null) {
                throw new ArgumentNullException(nameof(request));
            }
            request.Timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CurrentCulture);

            var content = JsonConvert.SerializeObject(request, Formatting.None, jsonSerializerSettings);

            var zmodel = await PostAsync(content, "icapi/Icconsumepayprequery").ConfigureAwait(false);
            logger.Trace($"ICconsumepayprequery:req{content},{JsonConvert.SerializeObject(zmodel)}");

            return zmodel;
        }

        /// <summary>
		/// 
		/// </summary>
		/// <param name="Cardno"></param>
		/// <param name="Mobile"></param>
		/// <returns></returns>
		public async Task<ICResult> IcremoveAsync(string Cardno, string Mobile)
        {
            string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.CurrentCulture);
            var data = new { phoneno = Mobile, cardno = Cardno, timestamp };
            var content = JsonConvert.SerializeObject(data);

            var zmodel = await PostAsync(content, "icapi/icremove").ConfigureAwait(false);
            logger.Trace($"Icremove:req{content},{JsonConvert.SerializeObject(zmodel)}");

            return zmodel;
        }
    }
}
